#! /usr/bin/python
#  Stackfull Interpreter 1.2
#  
#  Copyright 2012 Lifeless Planet Software <lifelessplanetsoftware@gmail.com>
#  
#  Stackfull is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 3 of the License, or
#  (at your option) any later version.
#  
#  Stackfull is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#  
#  

import sys 
import os
import random
import collections
import time

def main(filename):
	
	stack = collections.deque()		#Stack is deque, because deque contains useful methods
									#for operation of the stack
	prog = []
	progc = 0
	
	labeltable = {}					#Dictionary for labels and gotos
	lastloc = 0
	elsef = False
	iff = False

	vartable = {}					#Dictionary for stored variables

	args = []
	tempstr = ""
	templine = ""
	between = False
	
	fob = open(filename)
	for line in fob.readlines():
		prog.append(line)
	fob.close()
	
	for item in prog:
		progline = item.split()
		if len(progline) == 0:
			"Empty line"
		elif progline[0] == "import":
			fob = open(progline[1])
			for line in fob.readlines():
				prog.append(line)
	
	for item in prog:
		progline = item.split()
		if len(progline) == 0:
			"Ignore"
		elif progline[0] == "label":
			labeltable[progline[1]] = progc
		progc += 1
			
	progc = 0
	
	while True:
		args = [0,0,0,0]
		progline = prog[progc].split()
		
		if len(progline) == 0:
			"Do nothing"
		
		# Pushing data to stack
		elif progline[0] == "pushint":
			stack.append(int(progline[1]))
		
		elif progline[0] == "pushbool":
			stack.append(bool(progline[1]))
		
		elif progline[0] == "pushstr":
			templine = prog[progc].rstrip()
			
			for char in templine:
				if char == "*" and between == False:
					between = True
				elif char == "*" and between == True:
					between = False
					break
				elif between == True:
					tempstr = tempstr + char
			stack.append(tempstr)
			tempstr = ""
		
		# Variable-related instructions

		elif progline[0] == "takeval":
			vartable[progline[1]] = stack.pop()
		
		elif progline[0] == "giveval":
			stack.append(vartable[progline[1]])	

		# Comment
		elif progline[0] == "//":
			"This is a comment"
			
		elif progline[0] == "import":
			"This is an import statement"
			
		elif progline[0] == "dump":
			print stack
		
		# Mathematic functions
		elif progline[0] == "add":
			args[0] = stack.pop()
			args[1] = stack.pop()
			stack.append(args[0]+args[1])
		
		elif progline[0] == "sub":
			args[0] = stack.pop()
			args[1] = stack.pop()
			stack.append(args[1]-args[0])

		elif progline[0] == "mul":
			args[0] = stack.pop()
			args[1] = stack.pop()
			stack.append(args[0]*args[1])
		
		elif progline[0] == "div":
			args[0] = stack.pop()
			args[1] = stack.pop()
			stack.append(args[1]/args[0])
		
		elif progline[0] == "rand":
			args[0] = stack.pop()
			args[1] = stack.pop()
			stack.append(random.randint(args[1], args[0]))
		
		#I/O functions
		elif progline[0] == "print":
			args[0] = stack.pop()
			print args[0]
			stack.append(args[0])
		
		elif progline[0] == "inputint":
			stack.append(input())
		
		elif progline[0] == "inputstr":
			stack.append(raw_input())
		
		#Stack control
		elif progline[0] == "dup":						#Duplicate value at top of the stack
			stack.append(stack[len(stack)-1])
		
		elif progline[0] == "pop":						#Discard value at top of the stack
			stack.pop()
		
		elif progline[0] == "swap":						#Swap top two values of a stack
			args[0] = stack.pop()
			args[1] = stack.pop()
				
			stack.append(args[0])
			stack.append(args[1])
		
		elif progline[0] == "rotate":					#Rotate stack one step
			stack.rotate(1)
		
		elif progline[0] == "reverse":					#Reverse stack
			stack.reverse()
		
		#String functions
		elif progline[0] == "cat":
			args[0] = stack.pop()
			args[1] = stack.pop()
			
			stack.append(str(args[0] + args[1]))
			
		elif progline[0] == "contains":	
			args[0] = stack.pop()
			args[1] = stack.pop()
			
			stack.append(args[1])
			stack.append(args[0])
			stack.append(args[0] in args[1])
		
		#Logicals and program flow
		elif progline[0] == "not":						#Not operator
			args[0] = stack.pop()
			stack.append(not args[0])
		
		elif progline[0] == "and":						#And operator
			args[0] = stack.pop()
			args[1] = stack.pop()
			stack.append(args[0] and args[1])
				
		elif progline[0] == "or":						#Or operator
			args[0] = stack.pop()
			args[1] = stack.pop()
			stack.append(args[0] or args[1])
		
		elif progline[0] == "equals":					#Test equality of top two values of a stack
			args[0] = stack.pop()
			args[1] = stack.pop()
				
			if args[0] == args[1]:
				stack.append(args[1])
				stack.append(args[0])
				stack.append(True)
			else:
				stack.append(args[1])
				stack.append(args[0])
				stack.append(False)
				
		elif progline[0] == "less":
			args[0] = stack.pop()
			args[1] = stack.pop()
			
			if args[1] < args[0]:
				stack.append(args[1])
				stack.append(args[0])
				stack.append(True)
			else:
				stack.append(args[1])
				stack.append(args[0])
				stack.append(False)
				
		elif progline[0] == "more":
			args[0] = stack.pop()
			args[1] = stack.pop()
			
			if args[1] > args[0]:
				stack.append(args[1])
				stack.append(args[0])
				stack.append(True)
			else:
				stack.append(args[1])
				stack.append(args[0])
				stack.append(False)
		
		elif progline[0] == "wait":
			args[0] = stack.pop()
			time.sleep(args[0])
			
		elif progline[0] == "if":
			iff = True
			args[0] = stack.pop()
			
			if args[0] == False:
				while True:
					progc += 1
					if "else" in prog[progc]:
						break
					elif "endif" in prog[progc]:
						iff = False
						break
						
				if prog[progc] == "else":
					elsef = True
					
		elif progline[0] == "else":
			if elsef:
				elsef = False
			else:
				while not "endif" in prog[progc]:
					progc += 1
				
		
		elif progline[0] == "goto":
			lastloc = progc
			progc = labeltable.get(progline[1])
			
		elif progline[0] == "label":
			"Ignore"
		
		elif progline[0] == "return":
			progc = lastloc
			if iff:
				while not "endif" in prog[progc]:
					progc += 1
		
		#Program ending and syntax errors/Special
		elif progline[0] == "end":						#End the program
			break
		
		elif progline[0] == "os":
			args[0] = stack.pop()
			stack.append(os.system(args[0]))
		
		elif progline[0] == "osvar":
			args[0] = stack.pop()
			stack.append(os.getenv(args[0]))
		
		else:											#Anything else is a syntax error
			print "Syntax error @", progc
			break 										#Break on syntax error, makes errors easier to find.
		progc += 1


if len(sys.argv) < 2:
	print "No source file specified!"
else:
	main(sys.argv[1])
